import cheerio from "cheerio";
import { iArg } from "../iArg";
import { iFetcher } from "../iFetcher";
import { fetchRawData } from "./fetchRawData.js";
import {eventHandler,EventCode} from "../event/eventHandler.js"


class ContestInfo {
  constructor(
    name: string = "",
    url: string = "",
    startTime: string = "",
    duration: string = "",
    ratedRange: string = ""
  ) {
    this.name = name;
    this.url = "https://atcoder.jp" + url;
    this.startTime = Date.parse(startTime);
    this.duration = duration;
    this.ratedRange = ratedRange;
  }
  name: string;
  url: string;
  startTime: number;
  duration: string;
  ratedRange: string;
}

class PermanentContestsInfoFetcher implements iFetcher {
  public data: ContestInfo[] = [];
  public async fetch(): Promise<string> {
    this.data=[]
    let htmlText = "";
    let requestUrl = "https://atcoder.jp/contests/"
    htmlText = await fetchRawData(requestUrl);
    if (htmlText === "") {
      return ""
    }
    let $ = cheerio.load(htmlText);
    let trEle = $("#contest-table-permanent").find("tbody").find("tr");
    try {
      for (let i = 0; i < trEle.length; i++) {
        this.data.push(
          new ContestInfo(
            trEle.eq(i).find("td").eq(0).find("a").text(),
            trEle.eq(i).find("td").eq(0).find("a").attr("href")
          )
        );
      }
    } catch (e) {
      if (e instanceof Error) {
        eventHandler.handle(EventCode.PAESE_RAW_DATA_EXCEPTION,
          `parse data from ${requestUrl} err`, new Error()
        )
      }
    }

    return JSON.stringify(this.data);
  }
}
class UpcomingContestsInfoFetcher implements iFetcher {
  public data: ContestInfo[] = [];
  public async fetch(): Promise<string> {
    this.data=[]
    let htmlText = "";
    let requestUrl="https://atcoder.jp/contests/"
    htmlText = await fetchRawData(requestUrl)
    if (htmlText === "") {
      return ""
    }
    let $ = cheerio.load(htmlText);
    let trEle = $("#contest-table-upcoming").find("tbody").find("tr");
    try{
      for (let i = 0; i < trEle.length; i++) {
        this.data.push(
          new ContestInfo(
            trEle.eq(i).find("td").eq(1).find("a").text(),
            trEle.eq(i).find("td").eq(1).find("a").attr("href"),
            trEle.eq(i).find("td").eq(0).text(),
            trEle.eq(i).find("td").eq(2).text(),
            trEle.eq(i).find("td").eq(3).text()
          )
        );
      }
    }catch (e) {
      if (e instanceof Error) {
        eventHandler.handle(EventCode.PAESE_RAW_DATA_EXCEPTION,
          `parse data from ${requestUrl} err`, new Error()
        )
      }
    }
    

    return JSON.stringify(this.data);
  }
}

class PastContestsInfoFetcher implements iFetcher {
  public data: ContestInfo[] = [];
  public async fetch(arg: iArg): Promise<string> {
    this.data=[]
    let { count } = arg;
    if (count === undefined) {
      return "";
    }
    let htmlText = "";
    for (let ind = 1; true; ind++) {
      let requestUrl=`https://atcoder.jp/contests/archive?page=${ind}`
      htmlText = await fetchRawData(requestUrl)
      if (htmlText === "") {
        break
      }
      let $ = cheerio.load(htmlText);
      try{
        let trEle = $("tbody").find("tr");
        if (trEle.length == 0) {
          break;
        }
        for (let i = 0; i < trEle.length; i++) {
          this.data.push(
            new ContestInfo(
              trEle.eq(i).find("td").eq(1).find("a").text(),
              trEle.eq(i).find("td").eq(1).find("a").attr("href"),
              trEle.eq(i).find("td").eq(0).text(),
              trEle.eq(i).find("td").eq(2).text(),
              trEle.eq(i).find("td").eq(3).text()
            )
          );
          count--;
          if (count == 0) {
            return JSON.stringify(this.data);
          }
      }
      }catch (e) {
        if (e instanceof Error) {
          eventHandler.handle(EventCode.PAESE_RAW_DATA_EXCEPTION,
            `parse data from ${requestUrl} err`, new Error()
          )
        }
      }
    }
    return JSON.stringify(this.data);
  }
}
class ContestInfoFetcherFactory {
  public static getFetcher(requestType: string): iFetcher | undefined {
    const type = requestType.split(".")[1];
    switch (type) {
      case "permanent":
        return new PermanentContestsInfoFetcher();
      case "upcoming":
        return new UpcomingContestsInfoFetcher();
      case "past":
        return new PastContestsInfoFetcher();
    }
    return undefined;
  }
}
export { ContestInfoFetcherFactory };
